
package com.hlkj.pay.app.merchant.ext.impl.heepay;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.framework.extension.executor.ExtensionExecutor;
import com.hlkj.framework.extension.scenario.BizScenario;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantOrderExtPt;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.heepay.constanct.HeePayConstant;
import com.hlkj.pay.app.merchant.ext.impl.heepay.constanct.HeePayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.heepay.dto.HeePayConfig;
import com.hlkj.pay.app.merchant.ext.impl.heepay.dto.HeePayOrderNotifyRes;
import com.hlkj.pay.app.merchant.ext.impl.heepay.dto.HeePayRefundOrderNotifyRes;
import com.hlkj.pay.app.merchant.ext.impl.heepay.handler.HeePayMerchantCommonParamsHandle;
import com.hlkj.pay.app.merchant.ext.impl.heepay.util.HeePaySignUtil;
import com.hlkj.pay.app.merchant.ext.impl.heepay.util.HynetUtil;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.dto.order.PayOrderChannelResultDto;
import com.hlkj.pay.dto.order.notify.CsOrderNotifyDto;
import com.hlkj.pay.dto.order.notify.RefundOrderNotifyDto;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.HttpRequestUtil;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 汇付订单操作
 * 
 * @author HlpayTeam
 * @date 2024/10/10 13:51
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = MerchantExtConstant.CHANNEL_HEEPAY)
public class HeePayMerchantOrderExtPt implements ChannelMerchantOrderExtPt {

    private final ExtensionExecutor extensionExecutor;

    private final HeePayMerchantCommonParamsHandle heePayMerchantCommonParamsHandle;

    private final IPayOrderService payOrderService;

    private final IMerchantApplicationService merchantApplicationService;

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelPayOrderContext.setRemark("当前支付方式不支持");
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.submitChannelPayOrder(channelPayOrderContext));
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        PayWayDO payWayDO = channelPayOrderQueryContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelPayOrderQueryContext.setRemark("当前支付方式不支持");
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.queryChannelPayOrder(channelPayOrderQueryContext));
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        PayWayDO payWayDO = channelPayOrderQueryContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelPayOrderQueryContext.setRemark("当前支付方式不支持");
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.closeChannelPayOrder(channelPayOrderQueryContext));
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        PayWayDO payWayDO = channelPayOrderQueryContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelPayOrderQueryContext.setRemark("当前支付方式不支持");
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.queryChannelClosePayOrder(channelPayOrderQueryContext));

    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        PayWayDO payWayDO = channelRefundPayOrderContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelRefundPayOrderContext.setRemark("当前支付方式不支持");
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.refundChannelPayOrder(channelRefundPayOrderContext));
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        PayWayDO payWayDO = channelRefundPayOrderContext.getPayWayDO();
        String heePay = heePayType(payWayDO);
        if (!StringUtils.hasText(heePay)) {
            channelRefundPayOrderContext.setRemark("当前支付方式不支持");
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
            return;
        }
        extensionExecutor.executeVoid(HeePayScenePayOrderExtPt.class, BizScenario.valueOf(heePay), ex -> ex.queryRefundChannelPayOrder(channelRefundPayOrderContext));
    }

    @Override
    public CommonResult<PayOrderChannelResultDto> orderStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        Map<String, String> params = HttpRequestUtil.requestFormParams(request);
        String response = JsonUtils.toJsonString(params);
        log.info("汇付宝收到支付订单回调,参数数据为 payOrderDO:{}", response);
        CommonResult<PayOrderChannelResultDto> payOrderDOCommonResult = CommonResult.success();

        CommonResult<HeePayConfig> commonResult = heePayMerchantCommonParamsHandle.heePayConfig(providerChannelConfigDO, true);
        // 配置转换
        HeePayConfig heliPayConfig = commonResult.getData();
        //快捷支付
        if (params.containsKey("encrypt_data")) {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetailBySubMchId(params.get("agent_id"));
            if (merchantAppChannelDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_CHANNEL_NOT_EXIST);
            }
            heePayMerchantCommonParamsHandle.heePayAppChannelParams(merchantAppChannelDO, heliPayConfig);

            try {

                String rspContent = HeePaySignUtil.decrypt(params.get("encrypt_data"), heliPayConfig.getPrivateKey());
                if (HeePaySignUtil.verify(rspContent, params.get("sign"), heliPayConfig.getPublicKey())) {
                    Map<String, String> rsp = HeePaySignUtil.getURLParameters(rspContent);

                    PayOrderDO updartePayOrderDO = new PayOrderDO();
                    PayOrderChannelResultDto payOrderChannelResultDto = new PayOrderChannelResultDto();
                    payOrderChannelResultDto.setUpdatePayOrderDO(updartePayOrderDO);
                    payOrderChannelResultDto.setCallBackBody(response);
                    if (StringUtils.hasText(rsp.get("status"))) {
                        switch (rsp.get("status")) {
                            case "SUCCESS":
                                updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                                updartePayOrderDO.setBankMsg(rsp.get("deal_note"));
                                break;
                            default:
                                updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                                updartePayOrderDO.setBankMsg(rsp.get("deal_note"));
                                break;
                        }
                    }
                    if (StringUtils.hasText(rsp.get("hy_deal_time"))) {
                        try {
                            updartePayOrderDO.setSuccessTime(DateUtils.shanghaiDate(rsp.get("hy_deal_time"), "yyyyMMddHHmmss"));
                        }
                        catch (Exception e) {
                            log.error("汇付宝 支付订单回调 时间格式化错误 dateTime:{},message:{}", rsp.get("hy_deal_time"), e.getMessage(),e);
                        }
                    }
                    updartePayOrderDO.setPayOrderNo(rsp.get("agent_bill_id"));
                    updartePayOrderDO.setInsOrderNo(rsp.get("hy_bill_no"));
                    if (StringUtils.hasText(rsp.get("pay_amt"))) {
                        updartePayOrderDO.setPayAmount(MerchantUtils.stringToBigDecimal(rsp.get("pay_amt")));
                    }
                    if (StringUtils.hasText(rsp.get("hy_auth_uid"))) {
                        updartePayOrderDO.setUserId(rsp.get("hy_auth_uid"));
                    }
                    payOrderDOCommonResult.setData(payOrderChannelResultDto);
                    log.info("汇付宝收到支付订单回调,解析后的订单数据为 payOrderDO:{}", JsonUtils.toJsonString(updartePayOrderDO));
                    return payOrderDOCommonResult;
                } else {
                    log.info("汇付宝支付订单回调验签不通过,signature:{}", response);
                    payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
                }
            } catch (Exception e) {
                e.printStackTrace();
                payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
            }
            return payOrderDOCommonResult;
        } else {
            try {
                boolean verify = HynetUtil.verifyMd5(params, heliPayConfig, HeePayConstant.PAY_ORDER_NOTIFY_FIELD);
                if (!verify) {
                    log.info("汇付宝支付订单回调验签不通过,signature:{}", response);
                    payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
                }
            }
            catch (Exception e) {
                e.printStackTrace();
                payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
            }
            HeePayOrderNotifyRes heliPayOrderQueryRes = JsonUtils.parseObject(response, HeePayOrderNotifyRes.class);
            PayOrderDO updartePayOrderDO = new PayOrderDO();
            PayOrderChannelResultDto payOrderChannelResultDto = new PayOrderChannelResultDto();
            payOrderChannelResultDto.setUpdatePayOrderDO(updartePayOrderDO);
            payOrderChannelResultDto.setCallBackBody(response);
            if (StringUtils.hasText(heliPayOrderQueryRes.getResult())) {
                switch (heliPayOrderQueryRes.getResult()) {
                    case "1":
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                        updartePayOrderDO.setBankMsg("");
                        break;
                    default:
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                        updartePayOrderDO.setBankMsg("");
                        break;
                }
            }
            if (StringUtils.hasText(heliPayOrderQueryRes.getDeal_time())) {
                try {
                    updartePayOrderDO.setSuccessTime(DateUtils.shanghaiDate(heliPayOrderQueryRes.getDeal_time(), "yyyyMMddHHmmss"));
                }
                catch (Exception e) {
                    log.error("汇付宝 支付订单回调 时间格式化错误 dateTime:{},message:{}", heliPayOrderQueryRes.getDeal_time(), e.getMessage(),e);
                }
            }
            updartePayOrderDO.setPayOrderNo(heliPayOrderQueryRes.getAgent_bill_id());
            updartePayOrderDO.setInsOrderNo(heliPayOrderQueryRes.getTrade_bill_no());
            updartePayOrderDO.setChannelOrderNo(heliPayOrderQueryRes.getJnet_bill_no());
            if (StringUtils.hasText(heliPayOrderQueryRes.getPay_amt())) {
                updartePayOrderDO.setPayAmount(MerchantUtils.stringToBigDecimal(heliPayOrderQueryRes.getPay_amt()));
            }
            if (StringUtils.hasText(heliPayOrderQueryRes.getPay_user())) {
                updartePayOrderDO.setUserId(heliPayOrderQueryRes.getPay_user());
            }
            payOrderDOCommonResult.setData(payOrderChannelResultDto);
            log.info("汇付宝收到支付订单回调,解析后的订单数据为 payOrderDO:{}", JsonUtils.toJsonString(updartePayOrderDO));
            return payOrderDOCommonResult;
        }
    }

    @Override
    public CommonResult<PayOrderChannelResultDto> orderStatusParse(HttpServletRequest request) {
        return null;
    }

    @Override
    public CommonResult<PayOrderChannelResultDto> merAuthParse(HttpServletRequest request) {
        return null;
    }

    @Override
    public PayOrderDO closeOrderStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        return null;
    }

    @Override
    public CommonResult<CsOrderNotifyDto> csOrderStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        return null;
    }

    @Override
    public CommonResult<RefundOrderNotifyDto> refundStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        Map<String, String> params = HttpRequestUtil.requestFormParams(request);
        String response = JsonUtils.toJsonString(params);
        log.info("汇付宝收到退款订单回调,参数数据为 payOrderDO:{}", response);
        String paramsConfig = providerChannelConfigDO.getParamsConfig();
        CommonResult<RefundOrderNotifyDto> payOrderDOCommonResult = CommonResult.success();
        try {
            CommonResult<HeePayConfig> commonResult = heePayMerchantCommonParamsHandle.heePayConfig(providerChannelConfigDO, true);
            // 配置转换
            HeePayConfig heliPayConfig = commonResult.getData();
            boolean verify = HynetUtil.verifyMd5LowerCase(params, heliPayConfig, HeePayConstant.REFUND_ORDER_NOTIFY_FIELD);
            if (!verify) {
                log.info("汇付宝支付退款回调验签不通过,signature:{}", response);
                payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            payOrderDOCommonResult.setCode(MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode());
        }
        HeePayRefundOrderNotifyRes heliPayRefundOrderQueryRes = JsonUtils.parseObject(response, HeePayRefundOrderNotifyRes.class);
        RefundOrderNotifyDto refundOrderNotifyDto=new RefundOrderNotifyDto();
        refundOrderNotifyDto.setCallBackBody(JsonUtils.toJsonString(params));
        RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
        refundOrderNotifyDto.setRefundOrder(updateRefundOrderDO);
        updateRefundOrderDO.setRefundOrderNo(heliPayRefundOrderQueryRes.getAgent_refund_bill_no());
        switch (heliPayRefundOrderQueryRes.getRefund_status()) {
            case "FAIL":
            case "fail":
                updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.FAIL.getCode());
                updateRefundOrderDO.setBankMsg(heliPayRefundOrderQueryRes.getMsg());
                break;
            case "REFUNDING":
            case "refunding":
                break;
            case "SUCCESS":
            case "success":
                updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                if (StringUtils.hasText(heliPayRefundOrderQueryRes.getHy_deal_time())) {
                    try {
                        updateRefundOrderDO.setSuccessTime(DateUtils.shanghaiDate(heliPayRefundOrderQueryRes.getHy_deal_time(), "yyyyMMddHHmmss"));
                    }
                    catch (Exception e) {
                        log.error("汇付宝退款订单查询返回 时间格式化错误 dateTime:{},message:{}", heliPayRefundOrderQueryRes.getHy_deal_time(), e.getMessage(),e);
                    }
                }
                break;
            default:
                updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
        }
        // if (StringUtils.hasText(heliPayRefundOrderQueryRes.g())) {
        // updateRefundOrderDO.setActualRefundAmount(MerchantUtils.stringToBigDecimal(heliPayRefundOrderQueryRes.getRefundCashAmount()));
        // }
        payOrderDOCommonResult.setData(refundOrderNotifyDto);
        log.info("汇付宝收到退款订单回调,解析后的订单数据为 payOrderDO:{}", JsonUtils.toJsonString(updateRefundOrderDO));
        return payOrderDOCommonResult;
    }

    @Override
    public String channelPayCode(PayWayDO payWayDO) {
        return heePayType(payWayDO);
    }

    @Override
    public Long queryChannelPayAppid(ChannelPayOrderContext channelPayOrderContext) {
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
        if (extra == null && StringUtils.hasText(payOrderDO.getExtra())) {
            extra = JsonUtils.parseObject(payOrderDO.getExtra(), PayOrderCommonParamReq.Extra.class);
        }
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByType(payWayDO.getSubType());
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        if (extra != null && payType.getCode().equals(PayEnums.PAY_TYPE.WECHAT.getCode())) {
            switch (scenePayType) {
                case JSAPI:
                    return providerChannelConfigDO.getWechatDefaultPubId();
                // case MINI_APP:
                case APP:
                case H5:
                    return providerChannelConfigDO.getWechatDefaultMiniId();
                default:
            }
        }
        return null;
    }

    @Override
    public String callBackResponse(CommonResult commonResult) {
        if (commonResult.isSuccess()) {
            return "ok";
        }
        else {
            return commonResult.getMsg();
        }
    }

    @Override
    public boolean wechatLink(ChannelPayOrderContext channelPayOrderContext) {
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
        if (extra != null && StringUtils.hasText(extra.getUserId())) {
            return false;
        }
        PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByType(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        // 只有微信 app h5才需要
        switch (payType) {
            case WECHAT:
                break;
            default:
                return false;
        }
        switch (scenePayType) {
            case APP:
            case H5:
                return true;
            default:
                return false;
        }
    }

    /**
     * 汇付支付方式路由
     * 
     * @param payWayDO
     * @return
     */
    private String heePayType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByCode(payWayDO.getCode());
        if (scenePayType == null) {
            return null;
        }
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        switch (scenePayType) {
            case SCAN:
                return HeePayExtConstant.SCAN;
            default:
                switch (payType) {
                    case WECHAT:
                        return HeePayExtConstant.WECHAT;
                    case ALIPAY:
                        return HeePayExtConstant.ALIPAY;
                    case UNION_APY:
                        return HeePayExtConstant.UNION;
                    case QUICK:
                        return HeePayExtConstant.QUICK;
                    default:
                        return null;
                }
        }
    }

}
